﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using lumo.display.object2D;

namespace lumo.display.light
{
    /// <summary>
    /// 
    /// </summary>
    public class Light : IPositionable2D, IColorable
    {
        /// <summary>
        /// Position
        /// </summary>
        private Vector2 _Position = Vector2.Zero;
        public Vector2 Position { get { return _Position; } set { _Position = value; } }
        public float X { get { return _Position.X; } set { _Position.X = value; } }
        public float Y { get { return _Position.Y; } set { _Position.Y = value; } }

        /// <summary>
        /// Radius
        /// </summary>
        public readonly int Radius   = 128;

        // Private variables
        internal RenderTarget2D LinearizedTarget;
        internal RenderTarget2D ProcessedTarget;
        private float Scale   = 1f;
        private int   RealRadius;
        private int   RealDiameter;

        /// <summary>
        /// Light constructor.
        /// </summary>
        /// <param name="GraphicsDevice"></param>
        internal Light(GraphicsDevice GraphicsDevice, int Radius = 128, float Scale = 1f)
        {
            // Set light parameters.
            this.Scale         = Scale;
            this.Radius        = Radius;
            this.RealRadius    = (int)(Radius / Scale);
            this.RealDiameter  = this.RealRadius * 2;

            // Create targets.
            LinearizedTarget = new RenderTarget2D(GraphicsDevice, this.RealDiameter, this.RealDiameter, false, SurfaceFormat.Color, DepthFormat.None);
            ProcessedTarget  = new RenderTarget2D(GraphicsDevice, this.RealDiameter, this.RealDiameter, false, SurfaceFormat.Color, DepthFormat.None);
        }

        /// <summary>
        /// Light constructor.
        /// </summary>
        /// <param name="GraphicsDevice"></param>
        internal void Apply(LightManager LightManager, Texture2D ImpassableTexture)
        {
            // Set variables.
            GraphicsDevice GraphicsDevice = LightManager.ParentComponent.GraphicsDevice;
            SpriteBatch    SpriteBatch    = LightManager.ParentComponent.SpriteBatch;

            //
            Vector2 RealPosition = _Position - LightManager.Origin;

            // Matrix for shader.
            Matrix M = Matrix.Identity;
            M *= Matrix.CreateOrthographicOffCenter(0, this.RealDiameter, this.RealDiameter, 0, -1000, 1000);
            LightManager.LinearizeEffect.Parameters["WorldViewProjectionMatrix"].SetValue(M);

            // Draw the temp texture
            GraphicsDevice.SetRenderTarget(ProcessedTarget);
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.None, null, null);
            SpriteBatch.Draw(ImpassableTexture, new Rectangle(0, 0, this.RealDiameter, this.RealDiameter), new Rectangle((int)RealPosition.X - Radius, (int)RealPosition.Y - Radius, 2 * Radius, 2 * Radius), Color.White);
            SpriteBatch.End();

            // Linearize Target
            GraphicsDevice.SetRenderTarget(LinearizedTarget);
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.None, null, LightManager.LinearizeEffect);
            SpriteBatch.Draw(ProcessedTarget, Vector2.Zero, Color.White);
            SpriteBatch.End();

            // Process Target
            GraphicsDevice.SetRenderTarget(ProcessedTarget);
            GraphicsDevice.Clear(new Color(0, 0, 0, 0));
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, SamplerState.LinearClamp, DepthStencilState.None, null, null);
            Rectangle Dest   = new Rectangle(0, 0, 0, this.RealDiameter);
            Rectangle Source = new Rectangle(0, 0, 1, this.RealDiameter);
            for (int x = 1; x <= this.RealRadius; x++)
            {
                Dest.X     = 0;
                Dest.Width = x;
                Source.X   = x - 1;
                SpriteBatch.Draw(LinearizedTarget, Dest, Source, Color.White);

                Dest.X     = this.RealDiameter - x;
                Source.X   = this.RealDiameter - x;
                SpriteBatch.Draw(LinearizedTarget, Dest, Source, Color.White);
            }
            SpriteBatch.End();
        }

        private Color _Color = Color.White;
        public Color Color { get { return _Color; } set { _Color = value; } }
        public byte ColorR { get { return _Color.R; } set { _Color.R = value; } }
        public byte ColorG { get { return _Color.G; } set { _Color.G = value; } }
        public byte ColorB { get { return _Color.B; } set { _Color.B = value; } }
        public byte ColorA { get { return _Color.A; } set { _Color.A = value; } }
    }
}
